/*
 *  Tiled Map Editor, (c) 2004-2008
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  Adam Turk <aturk@biggeruniverse.com>
 *  Bjorn Lindeijer <bjorn@lindeijer.nl>
 */

package tiled.view;

// for console logging

import java.awt.Polygon;
import java.util.Iterator;

import javax.swing.SwingConstants;

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;

import tiled.core.*;
//import tiled.io.TiledLogger;
import tiled.mapeditor.selection.SelectionLayer;
import tiled.util.Converter;

/**
 * A View for displaying Hex based maps.
 * There are four possible layouts for the hexes. These are called
 * tile alignment and are named 'top', 'bottom', 'left' and 'right'.
 * The name designates the border where the first row or column of
 * hexes is aligned with a flat side. I.e. 'left' and 'right' result
 * in hexes with the pointy sides up and down and the first row
 * either aligned left or right:
 * <pre>
 *   /\
 *  |  |
 *   \/
 * </pre>
 * And 'top' and 'bottom' result in hexes with the pointy sides to
 * the left and right and the first column either aligned top or bottom:
 * <pre>
 *   __
 *  /  \
 *  \__/
 *
 * </pre>

 * <p>Here is an example 2x2 map with top alignment:
 * <pre>
 *   ___
 *  /0,0\___
 *  \___/1,0\
 *  /0,1\___/
 *  \___/1,1\
 *      \___/
 * </pre>
 *
 * <p>The icon width and height refer to the total width and height
 * of a hex (i.e the size of the enclosing rectangle).
 *
 * @version $Id$
 */
public class HexMapView extends MapView
{
	public static final int ALIGN_TOP = 1;
    public static final int ALIGN_BOTTOM = 2;
    public static final int ALIGN_RIGHT = 3;
    public static final int ALIGN_LEFT = 4;
    
    private static final int OBJECT_FOREGROUND = SWT.COLOR_GRAY;

    private static final double HEX_SLOPE = Math.tan(Math.toRadians(60));

    private int mapAlignment;
    /* hexEdgesToTheLeft:
     * This means a layout like this:     __
     *                                   /  \
     *                                   \__/
     * as opposed to this:     /\
     *                        |  |
     *                         \/
     */
    private boolean hexEdgesToTheLeft;
    private boolean alignedToBottomOrRight;

    /**
     * Creates a new hexagonal map view that displays the specified map.
     *
     * @param map The map to be displayed by this map view.
     */
    public HexMapView(Composite parent, Map map) {
        super(parent,map);

        //mapAlignment = map.getAlignment();
        mapAlignment = ALIGN_TOP;
        hexEdgesToTheLeft = false;
        if ( mapAlignment == ALIGN_TOP
            || mapAlignment == ALIGN_BOTTOM ) {
            hexEdgesToTheLeft = true;
        }
        alignedToBottomOrRight = false;
        if ( mapAlignment == ALIGN_BOTTOM
            || mapAlignment == ALIGN_RIGHT ) {
            alignedToBottomOrRight = true;
        }

        //TiledLogger.getLogger().info("HexMapView created");
    }

    /**
     * The scroll increment when clicking in the trough of a scrollbar,
     * that is scrolling a page. The amount is set to the size
     * of the completely visible hexes in the viewport.
     *
     * @param visibleRect Current viewport rectangle.
     * @param orientation SwingConstants.VERTICAL or HORIZONTAL.
     * @param direction > 0 = scrolling down; < 0 = scrolling up.
     *
     * @return Scroll amount in pixels.
     */
    public int getScrollableBlockIncrement(Rectangle visibleRect,
            int orientation, int direction) {
        Point tsize = getEffectiveTileSize();
        int border = showGrid ? 1 : 0;
        int tq = getThreeQuarterHex();
        int hWidth = (int)(tsize.x / 2 + 0.49) + border;
        int hHeight = (int)(tsize.y / 2 + 0.49) + border;

        //TiledLogger.getLogger().info(
        //    "ScrollBlock " + orientation + "/" + direction);
        //TiledLogger.getLogger().info(
        //    "visibleRect " + visibleRect.width + "," + visibleRect.height );
        //TiledLogger.getLogger().info(
        //    "tq " + tq + " border " + border + " height " + tsize.height);
        //TiledLogger.getLogger().info(
        //    "BlockInc w "
        //    + ((int)(visibleRect.width / (tq + border)) * (tq + border))
        //    + ", h "
        //    + ((int)(visibleRect.height / (tsize.height + border))
        //        * (tsize.height + border)));

        if (orientation == SwingConstants.VERTICAL ) {
            if ( hexEdgesToTheLeft ) {
                return (visibleRect.height - hHeight)
                    / (tsize.y + border)
                    * (tsize.y + border);
            } else {
                return (visibleRect.height -hHeight) / (tq + border)
                    * (tq + border);
            }
        } else {
            if ( hexEdgesToTheLeft ) {
                return (visibleRect.width - hWidth) / (tq + border)
                    * (tq + border);
            } else {
                return (visibleRect.width - hWidth)
                    / (tsize.x + border)
                    * (tsize.x + border);
            }
        }
    }

    /**
     * The scroll increment when clicking on the arrows of a scrollbar,
     * that is scrolling one hex horizontically or vertically.
     *
     * @param visibleRect Current viewport rectangle.
     * @param orientation SwingConstants.VERTICAL or HORIZONTAL.
     * @param direction > 0 = scrolling down; < 0 = scrolling up.
     *
     * @return Scroll amount in pixels.
     */
    public int getScrollableUnitIncrement(Rectangle visibleRect,
            int orientation, int direction) {
        //TiledLogger.getLogger().info(
        //    "ScrollUnit " + orientation + "/" + direction);
        Point tsize = getEffectiveTileSize();
        int border = showGrid ? 1 : 0;
        int tq = getThreeQuarterHex();
        if (orientation == SwingConstants.VERTICAL ) {
            if ( hexEdgesToTheLeft ) {
                return tsize.y + border;
            } else {
                return tq + border;
            }
        } else {
            if ( hexEdgesToTheLeft ) {
                return tq + border;
            } else {
                return tsize.x + border;
            }
        }
    }

    /**
     * The total size of the viewport so that all tiles of
     * the map fit in.
     *
     * @return Width and Height as Point.
     */
    public Point getPreferredSize() {
        Point tsize = getEffectiveTileSize();
        int w;
        int h;
        int border = showGrid ? 1 : 0;
        int tq = getThreeQuarterHex();
        int oq = getOneQuarterHex();

        if ( hexEdgesToTheLeft ) {
            //TiledLogger.getLogger().info(
            //    " twidth*3/4 " + tq
            //    + " twidth/4 " + oq
            //    + " theight/2 " + ((int)(tsize.height / 2 + 0.49)));

            w = map.getWidth() * (tq + border) + oq + border;
            h = map.getHeight() * (tsize.y + border)
                + (int)(tsize.y / 2 + 0.49) + border;
        } else {
            w = map.getWidth() * (tsize.x + border)
                + (int)(tsize.x / 2 + 0.49) + border;
            h = map.getHeight() * (tq + border) + oq + border;
        }

        //TiledLogger.getLogger().info("size " + w + "," + h);

        return new Point(w, h);
    }

    /**
     * Paint one layer to the viewport.
     *
     * @param g2d The graphics context, i.e. where to paint.
     * @param layer The layer to paint. Can be a special layer
     *        like the selection layer.
     */
    protected void paintLayer(GC g2d, TileLayer layer) {
        // Determine area to draw from clipping rectangle
        Point tsize = getEffectiveTileSize();
        // int toffset = showGrid ? 1 : 0;

        Rectangle clipRect = g2d.getClipping();

        //TiledLogger.getLogger().info("clip " + clipRect.x + "," + clipRect.y
        //    + "-" + clipRect.width + "," + clipRect.height);

        Point topLeft = screenToTileCoords(
                (int)clipRect.x, (int)clipRect.y);
        Point bottomRight = screenToTileCoords(
                (int)clipRect.x, (int)clipRect.y);
        int startX = (int)topLeft.x;
        int startY = (int)topLeft.y;
        int endX = (int)(bottomRight.x);
        int endY = (int)(bottomRight.y);
        if ( startX < 0 ) {
            startX = 0;
        }
        if ( startY < 0 ) {
            startY = 0;
        }
        if ( endX >= map.getWidth()) {
            endX = map.getWidth() - 1;
        }
        if ( endY >= map.getHeight()) {
            endY = map.getHeight() - 1;
        }

        //TiledLogger.getLogger().info("index " + startX + "," + startY
        //    + "-" + endX + "," + endY);

        Polygon gridPoly;
        double gx;
        double gy;
        for (int y = startY; y <= endY; y++) {
            for (int x = startX; x <= endX; x++) {
                Tile t = layer.getTileAt(x, y);

                if (t != null) {
                    if (layer.getClass() == SelectionLayer.class) {
                        //TiledLogger.getLogger().info(
                        //    "selection tile at " + x + "," + y);
                        gridPoly = createGridPolygon(x, y, 0);
                        g2d.fillPolygon(Converter.getPolygonArray(gridPoly));
                    } else {
                        Point screenCoords = getTopLeftCornerOfTile(x, y);
                        gx = screenCoords.x;
                        gy = screenCoords.y;
                        //TiledLogger.getLogger().info(
                        //    "image tile at " + x + "," + y
                        //    + " at " + gx + "," + gy);
                        RenderingUtil.drawTile(g2d, t, (int)gx, (int)(gy + tsize.y),
                            zoom);
                    }
                }
            }
        }
    }

    /**
     * Paint one layer to the viewport. Is this function used?
     * Not implemented!
     *
     * @param g2d The graphics context, i.e. where to paint.
     * @param og What is that?
     */
    protected void paintLayer(GC g2d, ObjectGroup og) {
        //TiledLogger.getLogger().info("called ?");
    }

    /**
     * @return The tile size in the view without border as Point.
     */
    private Point getEffectiveTileSize() {
        //TiledLogger.getLogger().info("size "
        //    + ((int)(map.getTileWidth() * zoom + 0.999)) + ","
        //    + ((int)(map.getTileHeight() * zoom + 0.999)));
        return new Point((int)(map.getTileWidth() * zoom + 0.999),
            (int)(map.getTileHeight() * zoom + 0.999));
    }

    /**
     * Together with getOneQuarterHex this gives the sizes of
     * one and three quarters in pixels in the interesting dimension.
     * If the layout is such that the hex edges point left and right
     * the interesting dimension is the width, otherwise it is the height.
     * The sum of one and three quarters equals always the total size
     * of the hex in this dimension.
     *
     * @return Three quarter of the tile size width or height (see above)
     * as integer.
     */
    private int getThreeQuarterHex() {
        int tq;
        if ( hexEdgesToTheLeft ) {
            tq = (int)(getEffectiveTileSize().x * 3.0 / 4.0 + 0.49);
        } else {
            tq = (int)(getEffectiveTileSize().y * 3.0 / 4.0 + 0.49);
        }

        return tq;
    }

    /**
     * Together with getThreeQuarterHex this gives the sizes of
     * one and three quarters in pixels in the interesting dimension.
     * If the layout is such that the hex edges point left and right
     * the interesting dimension is the width, otherwise it is the height.
     * The sum of one and three quarters equals always the total size
     * of the hex in this dimension.
     *
     * @return One quarter of the tile size width or height (see above)
     * as integer.
     */
    private int getOneQuarterHex() {
        int oq;
        if ( hexEdgesToTheLeft ) {
            oq = getEffectiveTileSize().x;
        } else {
            oq = getEffectiveTileSize().y;
        }

        return oq - getThreeQuarterHex();
    }

    /**
     * Paint the grid to the viewport.
     *
     * @param g2d The graphics context, i.e. where to paint.
     */
    protected void paintGrid(GC g2d) {
        g2d.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));
        Point tileSize = getEffectiveTileSize();

        // Determine area to draw from clipping rectangle
        Rectangle clipRect = g2d.getClipping();
        Point topLeft = screenToTileCoords(
                (int)clipRect.x, (int)clipRect.y);
        Point bottomRight = screenToTileCoords(
                (int)clipRect.x, (int)clipRect.y);
        int startX = (int)topLeft.x;
        int startY = (int)topLeft.y;
        int endX = (int)(bottomRight.x);
        int endY = (int)(bottomRight.y);

        //TiledLogger.getLogger().info(
        //    "  scrn " + clipRect.getMinX() + "," + clipRect.getMinY()
        //    + "-" + clipRect.getMaxX() + "," + clipRect.getMaxY());
        //TiledLogger.getLogger().info(
        //    "  tile " + startX + "," + startY + "-" + endX + "," + endY);

        if ( startX < 0 ) {
            startX = 0;
        }
        if ( startY < 0 ) {
            startY = 0;
        }
        if ( endX >= map.getWidth()) {
            endX = map.getWidth() - 1;
        }
        if ( endY >= map.getHeight()) {
            endY = map.getHeight() - 1;
        }

        //TiledLogger.getLogger().info("  tile " + startX + "," + startY
        //    + "-" + endX + "," + endY);

        int dy = 0;
        int dx = 0;
        Polygon grid;

        if ( hexEdgesToTheLeft ) {
            for (int x = startX; x <= endX; x++) {
                grid = createGridPolygon(x, startY, 1);
                for (int y = startY; y <= endY; y++) {
                    g2d.drawPolygon(Converter.getPolygonArray(grid));
                    grid.translate(0, tileSize.y + 1);
                }
            }
        } else {
            for (int y = startY; y <= endY; y++) {
                grid = createGridPolygon(startX, y, 1);
                for (int x = startX; x <= endX; x++) {
                    g2d.drawPolygon(Converter.getPolygonArray(grid));
                    grid.translate(tileSize.x + 1, 0);
                }
            }
        }
    }

    /**
     * Paint coordinates.
     * This should draw tiny coordinates in every hex tile.
     * Not implemented.
     *
     * @param g2d The graphics context, i.e. where to paint.
     */
    protected void paintCoordinates(GC g2d) {
        // TODO: Implement paintCoordinates for HexMapView
        //TiledLogger.getLogger().info("NOT IMPLEMENTED");
    }

    /**
     * Compute the resulting tile coords, i.e. map coordinates,
     * from a point in the viewport. This function works for some
     * coords off the map, i.e. it works for the tile coord -1
     * and for coords larger than the map size.
     *
     * @param screenX The x coordinate of a point in the viewport.
     * @param screenY The y coordinate of a point in the viewport.
     *
     * @return The corresponding tile coords as Point.
     */
    public Point screenToTileCoords(int screenX, int screenY) {
        //TiledLogger.getLogger().info(
          //  "screen coords " + screenX + "," + screenY);

        int tx = 0;
        int ty = 0;
        int border = showGrid ? 1 : 0;
        Point tileSize = getEffectiveTileSize();
        int tileWidth = tileSize.x + border;
        int tileHeight = tileSize.y + border;
        int hWidth = (int)(tileWidth / 2 + 0.49) + border;
        int hHeight = (int)(tileHeight / 2 + 0.49) + border;
        Point [] fourPoints = new Point [4];
        Point [] fourTiles = new Point [4];

        final int x = screenX;
        final int y = screenY;

        // determine the two columns of hexes we are between
        // we are between col and col+1.
        // col == -1 means we are in the strip to the left
        //   of the centers of the hexes of column 0.
        int col = 0;
        if ( x < hWidth ) {
            col = -1;
        } else {
            if ( hexEdgesToTheLeft ) {
                col = (int)((x - hWidth)
                    / (double)(getThreeQuarterHex() + border) + 0.001);
            } else {
                col = (int)((x - hWidth) / (double)tileWidth + 0.001);
            }
        }

        // determine the two rows of hexes we are between
        int row = 0;
        if ( y < hHeight ) {
            row = -1;
        } else {
            if ( hexEdgesToTheLeft ) {
                row = (int)((y - hHeight) / (double)tileHeight + 0.001);
            } else {
                row = (int)((y - hHeight)
                    / (double)(getThreeQuarterHex() + border) + 0.001);
            }
        }

        //TiledLogger.getLogger().info("  columns " + col + "/" + (col + 1));
        //TiledLogger.getLogger().info("  rows " + row + "/" + (row + 1));

        // now take the four surrounding points and
        // find the one having the minimum distance to x,y
        fourTiles [0] = new Point(col, row);
        fourTiles [1] = new Point(col, row + 1);
        fourTiles [2] = new Point(col + 1, row);
        fourTiles [3] = new Point(col + 1, row + 1);

        fourPoints [0] = tileToScreenCoords(col, row);
        fourPoints [1] = tileToScreenCoords(col, row + 1);
        fourPoints [2] = tileToScreenCoords(col + 1, row);
        fourPoints [3] = tileToScreenCoords(col + 1, row + 1);

        // find point with min.distance
        double minDist = 2 * (map.getTileWidth() + map.getTileHeight());
        int minI = 5;
        //TiledLogger.getLogger().info("  init Min " + minDist);
        for ( int i = 0; i < fourPoints.length; i++ ) {
            if ( distance(fourPoints [i], x, y) < minDist ) {
                minDist = distance(fourPoints [i], x, y);
                minI = i;
            }

            //TiledLogger.getLogger().info("  min.pt " + fourPoints [minI].x
            //    + "," + fourPoints [minI].getY() + " index " + minI
            //    + " at dist " + minDist);
        }

        // get min point
        tx = (int)(fourTiles [minI].x);
        ty = (int)(fourTiles [minI].y);

        //TiledLogger.getLogger().info("  -> tile coords " + tx + "," + ty);

        return new Point(tx, ty);
    }
    
    /**
     * Returns the distance from this <code>Point2D</code> to 
     * a specified point.
     *
     * @param px the X coordinate of the specified point to be measured
     *           against this <code>Point2D</code>
     * @param py the Y coordinate of the specified point to be measured
     *           against this <code>Point2D</code>
     * @return the distance between this <code>Point2D</code>
     * and a specified point.
     * @since 1.2
     */
    public double distance(Point point, double px, double py) {
		px -= point.x;
		py -= point.y;
		return Math.sqrt(px * px + py * py);
    }

    /**
     * Repaint a region of the viewport.
     * This function has been disabled. I have tried it
     * but it seems to repaint with some offset.
     *
     * @param region The rectangle of the viewport to be repainted.
     */
    public void repaintRegion(Rectangle region) {
        super.repaintRegion(region);

        //TiledLogger.getLogger().info(
        //    "region " + region.getMinX() + "," + region.getMinY()
        //    + "-" + region.getMaxX() + "," + region.getMaxY()
        //    + " zoom " + zoom);

        // // This code should work. I've disabled it because of general problems with the view refresh.
        // // Point2D topLeft=getTopLeftCornerOfTile((int) region.getMinX(),(int) region.getMinY(),zoom);
        // // Point2D bottomRight=getTopLeftCornerOfTile((int) region.getMaxX(),(int) region.getMaxY(),zoom);
        // Point2D topLeft=getTopLeftCornerOfTile((int) region.getMinX(),(int) region.getMinY());
        // Point2D bottomRight=getTopLeftCornerOfTile((int) region.getMaxX(),(int) region.getMaxY());
        //
        // // Point tileSize=getTileSize(zoom);
        // Point tileSize=getTileSize();
        // int width=(int) (bottomRight.x-topLeft.x+tileSize.getWidth());
        // int height=(int) (bottomRight.getY()-topLeft.getY()+tileSize.getHeight());
        //
        // Rectangle dirty=new Rectangle((int) topLeft.x,(int) topLeft.getY(),width,height);
        //
        // repaint(dirty);
    }


    /**
     * Returns a hexagon at the given tile coordinates.
     *
     * @param tx The x coordinate of the tile.
     * @param ty The y coordinate of the tile.
     * @param border 0 = no border, 1 = with border line.
     *
     * @return A hexagon structure as Polygon.
     */
    protected Polygon createGridPolygon(int tx, int ty, int border) {
        Point tileSize = getEffectiveTileSize();
        Polygon poly = new Polygon();
        Point p = getTopLeftCornerOfTile(tx, ty);
        int topLeftX = (int)(p.x);
        int topLeftY = (int)(p.y);

        //TiledLogger.getLogger().info("hex at " + topLeftX + "," + topLeftY);

        int tq = getThreeQuarterHex();
        int oq = getOneQuarterHex();

        // Go round the sides clockwise
        if ( hexEdgesToTheLeft ) {
            int hh = (int)(tileSize.y / 2 + 0.49);

            poly.addPoint(topLeftX - 1, topLeftY + hh - 1);
            poly.addPoint(topLeftX + oq - 1, topLeftY - 1);
            poly.addPoint(topLeftX + tq, topLeftY - 1);
            poly.addPoint(topLeftX + tileSize.x, topLeftY + hh - 1);
            poly.addPoint(topLeftX + tq, topLeftY + tileSize.y);
            poly.addPoint(topLeftX + oq - 1, topLeftY + tileSize.y);
        } else {
            int hh = (int)(tileSize.x / 2 + 0.49);

            poly.addPoint(topLeftX + hh - 1, topLeftY - 1);
            poly.addPoint(topLeftX + tileSize.x, topLeftY + oq - 1);
            poly.addPoint(topLeftX + tileSize.x, topLeftY + tq);
            poly.addPoint(topLeftX + hh - 1, topLeftY + tileSize.y);
            poly.addPoint(topLeftX - 1, topLeftY + tq);
            poly.addPoint(topLeftX - 1, topLeftY + oq - 1);
        }

        return poly;
    }

    /**
     * Get the point at the top left corner of the bounding rectangle of this
     * hex.
     *
     * @param x The x coordinate of the tile.
     * @param y The y coordinate of the tile.
     *
     * @return The top left corner of the enclosing rectangle of the hex
     *         in screen coordinates as Point.
     */
    private Point getTopLeftCornerOfTile(int x, int y) {
        //TiledLogger.getLogger().info("tile coords " + x + "," + y);

        Point tileSize = getEffectiveTileSize();
        int w = tileSize.x;
        int h = tileSize.y;
        int xx;
        int yy;

        if ( hexEdgesToTheLeft ) {
            xx = x * getThreeQuarterHex();
            yy = y * h;
        } else {
            xx = x * w;
            yy = y * getThreeQuarterHex();
        }

        if ( showGrid ) {
            xx += x + 1;
            yy += y + 1;
        }

        if ((Math.abs(x % 2) == 1 && mapAlignment == ALIGN_TOP)
            || (x % 2 == 0 && mapAlignment == ALIGN_BOTTOM)) {
            yy += (int)(h / 2.0 + 0.49);
        }
        if ((Math.abs(y % 2) == 1 && mapAlignment == ALIGN_LEFT)
            || (y % 2 == 0 && mapAlignment == ALIGN_RIGHT)) {
            xx += (int)(w / 2.0 + 0.49);
        }

        //TiledLogger.getLogger().info(
        //    "  -> screen coords " + xx + "," + yy + " zoom " + zoom);

        return new Point(xx, yy);
    }

    /**
     * Returns the location (center) on screen for the given tile.
     * Works also for hypothetical tiles off the map.
     * The zoom is accounted for.
     *
     * @param x The x coordinate of the tile.
     * @param y The y coordinate of the tile.
     *
     * @return The point at the centre of the Hex as Point.
     */
    public Point tileToScreenCoords(int x, int y) {
        Point p = getTopLeftCornerOfTile(x, y);
        Point tileSize = getEffectiveTileSize();
        return new Point(
            (int)(p.x) + (int)(tileSize.x / 2 + 0.49),
            (int)(p.y) + (int)(tileSize.y / 2 + 0.49));
    }

    public Point screenToPixelCoords(int x, int y) {
        return new Point(
                (int) (x / zoom), (int) (y / zoom));
    }

    protected void paintPropertyFlags(GC g2d, TileLayer layer) {
        // TODO: Implement property flags painting for HexMapView
    }

    protected void paintObjectGroup(GC g, ObjectGroup og) {
        // NOTE: Direct copy from OrthoMapView (candidate for generalization)
        Iterator<?> itr = og.getObjects();

        while (itr.hasNext()) {
            MapObject mo = (MapObject) itr.next();
            double ox = mo.getX() * zoom;
            double oy = mo.getY() * zoom;

            if (mo.getWidth() == 0 || mo.getHeight() == 0) {
            	g.setAntialias(SWT.ON);
                g.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));
                g.fillOval((int) ox + 1, (int) oy + 1,
                        (int) (10 * zoom), (int) (10 * zoom));
                g.setBackground(Display.getDefault().getSystemColor(OBJECT_FOREGROUND));
                g.fillOval((int) ox, (int) oy,
                        (int) (10 * zoom), (int) (10 * zoom));
            	g.setAntialias(SWT.OFF);
            } else {
            	g.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));
                g.drawRectangle((int) ox + 1, (int) oy + 1,
                    (int) (mo.getWidth() * zoom),
                    (int) (mo.getHeight() * zoom));
                g.setForeground(Display.getDefault().getSystemColor(OBJECT_FOREGROUND));
                g.drawRectangle((int) ox, (int) oy,
                    (int) (mo.getWidth() * zoom),
                    (int) (mo.getHeight() * zoom));
            }
            if (zoom > 0.0625) {
                final String s = mo.getName() != null ? mo.getName() : "(null)";
                g.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));
                g.drawString(s, (int) (ox - 5) + 1, (int) (oy - 5) + 1);
                g.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE));
                g.drawString(s, (int) (ox - 5), (int) (oy - 5));
            }
        }
    }
}
